{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Stabilizer code tutorial\n",
    "This examples goes over quantum error correction using stabilizer code.\n",
    "\n",
    "Useful references include:\n",
    "* Stabilizer Codes and Quantum Error Correction by Daniel Gottesman (https://thesis.library.caltech.edu/2900/2/THESIS.pdf) and its errata (https://www2.perimeterinstitute.ca/personal/dgottesman/thesis-errata.html)\n",
    "* Stabilizer code report (https://cs269q.stanford.edu/projects2019/stabilizer_code_report_Y.pdf)\n",
    "* Quantum Computing, a Gentle Introduction by Eleanor G. Rieffel and Wolfgang H. Polak. In particular chapter 11."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    import cirq\n",
    "except ImportError:\n",
    "    print(\"installing cirq...\")\n",
    "    !pip install --quiet cirq\n",
    "    print(\"installed cirq.\")\n",
    "    import cirq\n",
    "\n",
    "from cirq.contrib.svg import SVGCircuit\n",
    "import examples.stabilizer_code as sc"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, let's look at a simple repetition code. We simply encode a single qubit by repeating it three times. The construction is beyond the scope of this tutorial and a good introduction can be found in chapter 11 of the book above.\n",
    "\n",
    "As described in section 11.1.1, the code can only correct bit flip errors (i.e. Pauli X) but cannot correct phase errors (i.e. Pauli Z). Let's build the code and look at the circuit that is generated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "findfont: Font family ['Arial'] not found. Falling back to DejaVu Sans.\n"
     ]
    },
    {
     "data": {
      "image/svg+xml": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"220.0\" height=\"150.0\"><line x1=\"30.0\" x2=\"190.0\" y1=\"25.0\" y2=\"25.0\" stroke=\"#1967d2\" stroke-width=\"1\" /><line x1=\"30.0\" x2=\"190.0\" y1=\"75.0\" y2=\"75.0\" stroke=\"#1967d2\" stroke-width=\"1\" /><line x1=\"30.0\" x2=\"190.0\" y1=\"125.0\" y2=\"125.0\" stroke=\"#1967d2\" stroke-width=\"1\" /><line x1=\"90.0\" x2=\"90.0\" y1=\"25.0\" y2=\"125.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"150.0\" x2=\"150.0\" y1=\"75.0\" y2=\"125.0\" stroke=\"black\" stroke-width=\"3\" /><rect x=\"10.0\" y=\"5.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" /><text x=\"30.0\" y=\"25.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14px\" font-family=\"Arial\">0: </text><rect x=\"10.0\" y=\"55.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" /><text x=\"30.0\" y=\"75.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14px\" font-family=\"Arial\">1: </text><rect x=\"10.0\" y=\"105.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" /><text x=\"30.0\" y=\"125.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14px\" font-family=\"Arial\">c: </text><circle cx=\"90.0\" cy=\"125.0\" r=\"10.0\" /><rect x=\"70.0\" y=\"5.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"90.0\" y=\"25.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"150.0\" cy=\"125.0\" r=\"10.0\" /><rect x=\"130.0\" y=\"55.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"150.0\" y=\"75.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text></svg>",
      "text/plain": [
       "<cirq.contrib.svg.svg.SVGCircuit at 0x7f4a837f1df0>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "code = sc.StabilizerCode(group_generators=['ZZI', 'ZIZ'], correctable_errors=['X'])\n",
    "\n",
    "additional_qubits = [cirq.NamedQubit(str(i)) for i in range(code.n - code.k)]\n",
    "unencoded_qubits = [cirq.NamedQubit('c')]\n",
    "qubits = additional_qubits + unencoded_qubits\n",
    "\n",
    "circuit = code.encode(additional_qubits, unencoded_qubits)\n",
    "\n",
    "SVGCircuit(circuit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We see a circuit that encodes a single qubit into three qubits with the same values. These are the code words. Let's double check that we are indeed getting a repetion code. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 becomes |000⟩\n",
      "1 becomes |111⟩\n"
     ]
    }
   ],
   "source": [
    "for initial_state in [0, 1]:\n",
    "    results = cirq.Simulator().simulate(circuit, qubit_order=qubits, initial_state=initial_state)\n",
    "    print('%d becomes %s' % (initial_state, cirq.dirac_notation(results.state_vector())))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also see that both code words commute with the generators 'ZZI' and 'ZIZ'. In other words, this is the definition of a stabilizer.\n",
    "\n",
    "Now, we will perturb the circuit by flipping only one qubit (let's say the middle one). We will then add a circuit that computes the syndrome and performs the correction. To do this, we need to have ancillas. We then look at the output of the circuit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"860.0\" height=\"290.0\"><line x1=\"30.0\" x2=\"830.0\" y1=\"45.0\" y2=\"45.0\" stroke=\"#1967d2\" stroke-width=\"1\" /><line x1=\"30.0\" x2=\"830.0\" y1=\"95.0\" y2=\"95.0\" stroke=\"#1967d2\" stroke-width=\"1\" /><line x1=\"30.0\" x2=\"830.0\" y1=\"145.0\" y2=\"145.0\" stroke=\"#1967d2\" stroke-width=\"1\" /><line x1=\"30.0\" x2=\"830.0\" y1=\"195.0\" y2=\"195.0\" stroke=\"#1967d2\" stroke-width=\"1\" /><line x1=\"30.0\" x2=\"830.0\" y1=\"245.0\" y2=\"245.0\" stroke=\"#1967d2\" stroke-width=\"1\" /><line x1=\"240.0\" x2=\"330.0\" y1=\"5.0\" y2=\"5.0\" stroke=\"black\" stroke-width=\"1\" /><line x1=\"240.0\" x2=\"330.0\" y1=\"285.0\" y2=\"285.0\" stroke=\"black\" stroke-width=\"1\" /><line x1=\"90.0\" x2=\"90.0\" y1=\"45.0\" y2=\"145.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"150.0\" x2=\"150.0\" y1=\"95.0\" y2=\"145.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"260.0\" x2=\"260.0\" y1=\"45.0\" y2=\"195.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"300.0\" x2=\"300.0\" y1=\"95.0\" y2=\"245.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"370.0\" x2=\"370.0\" y1=\"145.0\" y2=\"195.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"430.0\" x2=\"430.0\" y1=\"145.0\" y2=\"245.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"550.0\" x2=\"550.0\" y1=\"45.0\" y2=\"245.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"670.0\" x2=\"670.0\" y1=\"95.0\" y2=\"245.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"790.0\" x2=\"790.0\" y1=\"145.0\" y2=\"245.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"240.0\" x2=\"240.0\" y1=\"5.0\" y2=\"15.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"330.0\" x2=\"330.0\" y1=\"5.0\" y2=\"15.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"240.0\" x2=\"240.0\" y1=\"275.0\" y2=\"285.0\" stroke=\"black\" stroke-width=\"3\" /><line x1=\"330.0\" x2=\"330.0\" y1=\"275.0\" y2=\"285.0\" stroke=\"black\" stroke-width=\"3\" /><rect x=\"10.0\" y=\"25.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" /><text x=\"30.0\" y=\"45.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14px\" font-family=\"Arial\">0: </text><rect x=\"10.0\" y=\"75.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" /><text x=\"30.0\" y=\"95.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14px\" font-family=\"Arial\">1: </text><rect x=\"10.0\" y=\"125.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" /><text x=\"30.0\" y=\"145.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14px\" font-family=\"Arial\">c: </text><rect x=\"10.0\" y=\"175.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" /><text x=\"30.0\" y=\"195.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14px\" font-family=\"Arial\">d0: </text><rect x=\"10.0\" y=\"225.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"0\" /><text x=\"30.0\" y=\"245.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"14px\" font-family=\"Arial\">d1: </text><circle cx=\"90.0\" cy=\"145.0\" r=\"10.0\" /><rect x=\"70.0\" y=\"25.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"90.0\" y=\"45.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"150.0\" cy=\"145.0\" r=\"10.0\" /><rect x=\"130.0\" y=\"75.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"150.0\" y=\"95.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><rect x=\"190.0\" y=\"75.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"210.0\" y=\"95.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"260.0\" cy=\"45.0\" r=\"10.0\" /><rect x=\"240.0\" y=\"175.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"260.0\" y=\"195.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"300.0\" cy=\"95.0\" r=\"10.0\" /><rect x=\"280.0\" y=\"225.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"300.0\" y=\"245.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"370.0\" cy=\"145.0\" r=\"10.0\" /><rect x=\"350.0\" y=\"175.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"370.0\" y=\"195.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"430.0\" cy=\"145.0\" r=\"10.0\" /><rect x=\"410.0\" y=\"225.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"430.0\" y=\"245.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><rect x=\"470.0\" y=\"225.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"490.0\" y=\"245.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"550.0\" cy=\"195.0\" r=\"10.0\" /><circle cx=\"550.0\" cy=\"245.0\" r=\"10.0\" /><rect x=\"530.0\" y=\"25.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"550.0\" y=\"45.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><rect x=\"590.0\" y=\"225.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"610.0\" y=\"245.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><rect x=\"590.0\" y=\"175.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"610.0\" y=\"195.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"670.0\" cy=\"195.0\" r=\"10.0\" /><circle cx=\"670.0\" cy=\"245.0\" r=\"10.0\" /><rect x=\"650.0\" y=\"75.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"670.0\" y=\"95.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><rect x=\"710.0\" y=\"175.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"730.0\" y=\"195.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text><circle cx=\"790.0\" cy=\"195.0\" r=\"10.0\" /><circle cx=\"790.0\" cy=\"245.0\" r=\"10.0\" /><rect x=\"770.0\" y=\"125.0\" width=\"40\" height=\"40\" stroke=\"black\" fill=\"white\" stroke-width=\"1\" /><text x=\"790.0\" y=\"145.0\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-size=\"18px\" font-family=\"Arial\">X</text></svg>",
      "text/plain": [
       "<cirq.contrib.svg.svg.SVGCircuit at 0x7f4a576b9460>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Append an error:\n",
    "circuit.append(cirq.X(qubits[1]))\n",
    "\n",
    "# Correct the error:\n",
    "ancillas = [cirq.NamedQubit(f\"d{i}\") for i in range(code.n - code.k)]\n",
    "circuit += code.correct(qubits, ancillas)\n",
    "\n",
    "SVGCircuit(circuit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "|00001⟩\n"
     ]
    }
   ],
   "source": [
    "results = cirq.Simulator().simulate(circuit, qubit_order=(qubits + ancillas), initial_state=0)\n",
    "print('%s' % (cirq.dirac_notation(results.state_vector())))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can see now 5 qubits. The first 3 qubits are the code word and the last 2 qubits are the syndrome. You can see that we have recovered the code words |000> and the syndrome is |01> resulting in a total state being |00001>. You can verify that the code works as expected. For example:\n",
    "* If there is no error, the syndrome should be |00>\n",
    "* Regardless of the input value, the syndrome should be the same for a given error\n",
    "* You can have a linear combination of error on the same qubit, as described in section 11.2.9\n",
    "\n",
    "We can also check that the syndrome is as predicted by the code given the errors."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{(-1, 1): ('X', 0), (1, -1): ('X', 1), (-1, -1): ('X', 2)}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "code.syndromes_to_corrections"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, we can decode the output by using a Pauli string measurement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "decoded=[0]\n"
     ]
    }
   ],
   "source": [
    "decoded = code.decode(qubits, ancillas, results.state_vector())\n",
    "print('decoded=%s' % (decoded))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, let's look at a more complicated code, the five-qubit code. We can verify that we get the same code words as equations 3.17 and 3.18 in the thesis. The reader can repeat the steps above to check that the syndrome is computed correctly and that the errors can be corrected. The unit tests do check these properties."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 becomes:\n",
      " |00000⟩ - 1|00011⟩ + |00101⟩ - 1|00110⟩ + |01001⟩ + |01010⟩ - 1|01100⟩ - 1|01111⟩ - 1|10001⟩ + |10010⟩ + |10100⟩ - 1|10111⟩ - 1|11000⟩ - 1|11011⟩ - 1|11101⟩ - 1|11110⟩\n",
      "\n",
      "1 becomes:\n",
      " |00001⟩ + |00010⟩ + |00100⟩ + |00111⟩ + |01000⟩ - 1|01011⟩ - 1|01101⟩ + |01110⟩ + |10000⟩ + |10011⟩ - 1|10101⟩ - 1|10110⟩ + |11001⟩ - 1|11010⟩ + |11100⟩ - 1|11111⟩\n",
      "\n"
     ]
    }
   ],
   "source": [
    "code = sc.StabilizerCode(\n",
    "    group_generators=['XZZXI', 'IXZZX', 'XIXZZ', 'ZXIXZ'], correctable_errors=['X', 'Z']\n",
    ")\n",
    "\n",
    "additional_qubits = [cirq.NamedQubit(str(i)) for i in range(code.n - code.k)]\n",
    "unencoded_qubits = [cirq.NamedQubit('c')]\n",
    "qubits = additional_qubits + unencoded_qubits\n",
    "\n",
    "circuit = code.encode(additional_qubits, unencoded_qubits)\n",
    "\n",
    "for initial_state in [0, 1]:\n",
    "    results = cirq.Simulator().simulate(circuit, qubit_order=qubits, initial_state=initial_state)\n",
    "    print('%d becomes:\\n %s\\n' % (initial_state, cirq.dirac_notation(4.0 * results.state_vector())))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
